package com.cjx.stars.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.injector.methods.SelectById;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cjx.stars.common.MyException;
import com.cjx.stars.common.Response;
import com.cjx.stars.common.ResponseUtils;
import com.cjx.stars.mapper.BlogMapper;
import com.cjx.stars.pojo.request.BlogUpdateRequest;
import com.cjx.stars.pojo.table.Blog;
import com.cjx.stars.pojo.table.BlogLike;
import com.cjx.stars.pojo.table.User;
import com.cjx.stars.pojo.vo.BlogVo;
import com.cjx.stars.pojo.vo.UserVo;
import com.cjx.stars.pojo.request.AddBlog;
import com.cjx.stars.service.*;
import com.cjx.stars.utils.FileUtils;
import com.cjx.stars.utils.RegexValidationUtils;
import com.cjx.stars.utils.UserHolder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.List;

import static com.cjx.stars.constant.FailMessage.*;
import static com.cjx.stars.constant.RedisConstant.BLOG_FEED_KEY;
import static com.cjx.stars.constant.RedisConstant.MESSAGE_BLOG_NUM_KEY;
import static com.cjx.stars.constant.SystemConstants.PAGE_SIZE;
import static com.cjx.stars.constant.SystemConstants.PROTOCOL_LENGTH;

/**
 * @author cjx
 * @description 针对表【blog】的数据库操作Service实现
 * @createDate 2024-04-03 19:28:10
 */
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog>
        implements BlogService {

    @Resource
    private BlogMapper blogMapper;
    @Resource
    private UserService userService;
    @Value("${stars.qiniu.url:null}")
    private String url;
    @Resource
    private BlogCommentsService blogCommentsService;
    @Resource
    @Lazy
    private BlogLikeService blogLikeService;
    @Resource
    private FollowService followService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Response<?> addBlog(AddBlog blog) {
        Blog insertBlog = new Blog();
        //1.判断标题和文章内容是否为空
        if (StrUtil.isBlank(blog.getTitle()) || StrUtil.isBlank(blog.getContent())) {
            throw new MyException(ERROR_PARAMETER_IS_BLACK);
        }
        //2.将图片上传并保留图片路径
        StringBuilder stringBuilder = new StringBuilder();
        if (blog.getImages() != null) {
            //2.1有图片才上传图片
            for (MultipartFile image : blog.getImages()) {
                String path = FileUtils.uploadFile(image);
                if (stringBuilder.isEmpty()) {
                    stringBuilder.append(path);
                } else {
                    stringBuilder.append(",").append(path);
                }
            }
            insertBlog.setImages(String.valueOf(stringBuilder));
        }
        //3.构造Blog对象
        insertBlog.setTitle(blog.getTitle());
        insertBlog.setContent(blog.getContent());
        Long userId = Long.valueOf(UserHolder.getUser().getUserId());
        insertBlog.setUserId(userId);
        insertBlog(insertBlog);
        //5.1查询此用户的粉丝id
        List<Long> followsIds =  followService.getFollowIds(userId);
        //5.2将博文id发送到每个粉丝的收件箱中
        for (Long followsId : followsIds) {
            String key = BLOG_FEED_KEY + followsId;
            stringRedisTemplate.opsForZSet().add(key, insertBlog.getId().toString(), System.currentTimeMillis());
        //5.3更新粉丝的博文收件箱数量消息
            String likeNumKey = MESSAGE_BLOG_NUM_KEY + followsId;
            Boolean hasKey = stringRedisTemplate.hasKey(likeNumKey);
            if (Boolean.TRUE.equals(hasKey)) {
                stringRedisTemplate.opsForValue().increment(likeNumKey);
            } else {
                stringRedisTemplate.opsForValue().set(likeNumKey, "1");
            }
        }
        return ResponseUtils.success();
    }

    public long insertBlog(Blog insertBlog) {
        //4.插入博文
        boolean isInsert = save(insertBlog);
        //5.如果插入成功将此博文id推送到粉丝收件箱中
        if (BooleanUtil.isFalse(isInsert)) {
            throw new MyException(FAILED_INSERT_BLOG);
        }
        return insertBlog.getId();
    }

    @Override
    public Response<?> getBlogList(int currentPage, String title) {
        LambdaQueryWrapper<Blog> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(Blog::getTitle, title);
        Page<BlogVo> page = selectPageBlog(currentPage, wrapper);
        return ResponseUtils.success(page);
    }

    @Override
    public BlogVo getBlogVoById(Long blogId) {
        //查询该id的博文
        Blog blog = getBlogById(blogId);
        if (blog == null) {
            return null;
//            throw new MyException(NOT_THE_BLOG);
        }
        BlogVo blogVo = BeanUtil.copyProperties(blog, BlogVo.class);
        //查询该博文的作者信息
        User author = userService.getById(blogVo.getUserId());
        if (author == null) {
            throw new MyException(NOT_THE_BLOG_AUTHOR);
        }
        UserVo userVo = BeanUtil.copyProperties(author, UserVo.class);
        boolean isLike = getIsLike(blogId, Long.valueOf(UserHolder.getUser().getUserId()));
        blogVo.setIsLike(isLike);
        blogVo.setAuthor(userVo);
        //给博客每一个图片增添fort路径
        //图片存在才操作
        if (StrUtil.isNotBlank(blog.getImages())) {
            String[] split = blogVo.getImages().split(",");
            StringBuilder stringBuilder = new StringBuilder();
            for (String string : split) {
                stringBuilder.append(url).append(string).append(",");
            }
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            blogVo.setImages(String.valueOf(stringBuilder));
        }
        return blogVo;
    }

    /**
     * 判断当前用户是否对该博文点赞
     *
     * @param blogId 博文id
     * @param userId 用户id
     * @return 是否点赞
     */
    private boolean getIsLike(Long blogId, Long userId) {
        long count = blogLikeService.count(new LambdaQueryWrapper<BlogLike>().eq(BlogLike::getBlogId, blogId)
                .eq(BlogLike::getUserId, userId));
        return count > 0;
    }

    @Override
    public void addCommentNum(Long blogId) {
        update(new UpdateWrapper<Blog>().eq("id", blogId).set("comments_num", getById(blogId).getCommentsNum() + 1));
    }

    @Override
    public Response<?> deleteBlog(Long blogId) {
        //1.判断此博文是否存在
        Blog blog = getById(blogId);
        if (blog == null) {
            throw new MyException(NOT_THE_BLOG);
        }
        //2.判断当前用户是否为该博文作者
        Long userId = Long.valueOf(UserHolder.getUser().getUserId());
        if (!userId.equals(blog.getUserId())) {
            throw new MyException(ERROR_INSUFFICIENT_PERMISSIONS);
        }
        //3.删除该博文
        boolean b = removeById(blogId);
        if (!b) {
            throw new MyException(FAILED_TO_DELETE_THE_BLOG_POST);
        }
        return ResponseUtils.success();

    }

    @Override
    public Response<?> updateBlog(BlogUpdateRequest blogUpdateRequest) {
        Long blogId = blogUpdateRequest.getId();
        String title = blogUpdateRequest.getTitle();
        String content = blogUpdateRequest.getContent();
        //1.数据格式校验
        if (RegexValidationUtils.checkId(blogId) && StrUtil.hasBlank(title, content)) {
            throw new MyException(PARAMETER_ABNORMAL);
        }
        //2.博文存在性校验
        Blog blog = getBlogById(blogId);
        //3.博文用户权限校验
        isUserInBlogAuthor(blog);
        //4.获取更新后的旧图片保留集合
        ArrayList<String> imageNameList = new ArrayList<>();
        if (StringUtils.isNotBlank(blogUpdateRequest.getImgStr())) {
            String imgStr = blogUpdateRequest.getImgStr();
            String[] imgs = imgStr.split(",");
            //4.1拆除 http://域名信息/ 前缀
            for (String img : imgs) {
                String fileName = img.substring(img.indexOf("/", PROTOCOL_LENGTH) + 1);
                imageNameList.add(fileName);
            }
        }
        //5.上传新添加的图片数据
        if (blogUpdateRequest.getImages() != null) {
            MultipartFile[] images = blogUpdateRequest.getImages();
            for (MultipartFile image : images) {
                String filename = FileUtils.uploadFile(image);
                imageNameList.add(filename);
            }
        }
        //6.封装Blog对象
        if (!imageNameList.isEmpty()) {
            //6.1封装图片信息
            String imageStr = StringUtils.join(imageNameList, ",");
            blog.setImages(imageStr);
        }
        //6.2封装内容信息
        blog.setContent(content);
        //6.3封装标题信息
        blog.setTitle(title);
        //7.修改此博文类
        int isSuccess = blogMapper.updateById(blog);
        if (isSuccess == 0) {
            throw new MyException(FAILED_TO_EDIT_THE_BLOG_POST);
        }
        return ResponseUtils.success();
    }

    @Override
    public Response<?> getMyBlogList(int currentPage) {
        Page<BlogVo> blogVoPage = selectPageBlog(currentPage, new LambdaQueryWrapper<Blog>().eq(Blog::getUserId, Long.valueOf(UserHolder.getUser().getUserId())));
        return ResponseUtils.success(blogVoPage);
    }

    /**
     * 判断此用户是否为该博文作者
     *
     * @param blog 博文信息
     */
    private void isUserInBlogAuthor(Blog blog) {
        if (!blog.getUserId().equals(Long.valueOf(UserHolder.getUser().getUserId()))) {
            throw new MyException(ERROR_INSUFFICIENT_PERMISSIONS);
        }
    }

    /**
     * 判断该博文是否存在数据库
     *
     * @param blogId 博文id
     * @return 博文信息
     */
    public Blog getBlogById(Long blogId) {
        return getById(blogId);
    }

    /**
     * 分页查询博文数据
     *
     * @param currentPage 分页数据
     * @param wrapper     查询条件
     * @return 博文数据
     */
    private Page<BlogVo> selectPageBlog(int currentPage, LambdaQueryWrapper<Blog> wrapper) {
        //条件分页查询博文数据
        Page<Blog> page = new Page<>(currentPage, PAGE_SIZE);
        Page<Blog> blogPage = blogMapper.selectPage(page, wrapper);
        List<Blog> blogList = blogPage.getRecords();
        List<BlogVo> blogVos = blogList.stream().map(blog -> BeanUtil.copyProperties(blog, BlogVo.class)).toList();
        List<Long> blogUserId = blogList.stream().map(Blog::getUserId).toList();
        for (BlogVo blogVo : blogVos) {
            //设置每条博文的封面图片
            //没图片则跳过
            if (StrUtil.isNotBlank(blogVo.getImages())) {
                String[] split = blogVo.getImages().split(",");
                blogVo.setCoverImage(url + split[0]);
            }
            boolean isLike = getIsLike(blogVo.getId(), Long.valueOf(UserHolder.getUser().getUserId()));
            blogVo.setIsLike(isLike);
        }
        Page<BlogVo> pageVo = new Page<>(currentPage, PAGE_SIZE);
        //不将records属性传递
        BeanUtil.copyProperties(blogPage, pageVo, "records");
        pageVo.setRecords(blogVos);
        return pageVo;
    }
}




